/**
 * combotree - jQuery EasyUI
 * 
 * Licensed under the GPL:
 *   http://www.gnu.org/licenses/gpl.txt
 *
 * Copyright 2010 stworthy [ stworthy@gmail.com ] 
 * 
 * Dependencies:
 * 	 tree
 * 
 */
(function($){
	function setSize(target){
		var opts = $.data(target, 'combotree').options;
		var combo = $.data(target, 'combotree').combotree;
		var content = $.data(target, 'combotree').content;
		if (!isNaN(opts.width)){
			var arrowWidth = combo.find('.combotree-arrow ui-icon ui-icon-triangle-1-s').outerWidth();
			var width = opts.width - arrowWidth - (combo.outerWidth() - combo.width());
			combo.find('input.combotree-text').width(width-16);
		}
		opts.treeWidth = opts.treeWidth||opts.width ;
		if (opts.treeWidth){
			content.width(opts.treeWidth);
		} else {
			content.width($.boxModel==true ? combo.outerWidth()-(content.outerWidth()-content.width()) : combo.outerWidth());
		}
		if (opts.treeHeight){
			content.height(opts.treeHeight);
		}
		content.find('>ul').__tree({
			url:opts.url,
			params:opts,
			target:target,
			onClick:function(node){
				var oldValue = combo.find('input.combotree-value').val();
				combo.find('input.combotree-value').val(node.id);
				combo.find('input.combotree-text').val(node.text);
				content.hide();
				if(isIE6()){
					content.next("iframe").hide();
				}
				
				$(target).empty().append("<option value='' selected></option>").append("<option value='"+node.id+"' >"+node.text+"</option>") ;
				$(target).val(node.id) ;
				
				opts.onSelect.call(target, node);
				if (oldValue != node.id){
					opts.onChange.call(target, node.id, oldValue);
				}
		
				if($.validation)$.validation.loadValidation($(target));
				if($(target).change)$(target).change();
			}
		});
	}
	
	var isIE6 = function(){
		if (jQuery.browser.msie) {
		   return parseInt(jQuery.browser.version)<=6 ;
		}
		return false ;
	}
	
	function init(target){
		
		$(target).hide();
		
		var span = $('<span class="combotree ui-widget"></span>').insertAfter(target);
		$('<input type="hidden" class="combotree-value"/>').appendTo(span);
		$('<input class="combotree-text" readonly="true"/>').appendTo(span);
		var arrow = $('<span class="combotree-arrow ui-icon ui-icon-triangle-1-s"></span>').appendTo(span);
		var content = $('<div class="ui-helper-reset ui-widget-content ui-corner-all combotree-content"><ul></ul></div>').appendTo(span);
		var iframe = null ;
		if(isIE6()){
			iframe = $("<iframe style='display:none;position: absolute;' src='about:blank'/>").appendTo(span);
		}

		$(target).data("validate_target",$(target).next('.combotree')) ;
		
		var name = $(target).attr('name');
		if (name){
			span.attr('name', name);
			$(target).removeAttr('name');
		}
		
		/**
		 * show tree panel
		 * 该方法与ui.select.multi.js有冲突
		 */
		function show(){
			content.css({
				display:'block',
				left:0,
				//left:span.offset().left,//span.offset().left,
				top:span.outerHeight()-1//span.offset().top
			});

			if(isIE6()){
				iframe.css({
					display:'block',
					left:0,
					top:span.outerHeight()-1,
					width:content.width(),
					height:content.height()
				});
			}
			
			$(document).unbind('.combotree').bind('click.combotree', function(){
				content.hide();
				if(isIE6())iframe.hide();
				//return false;//注释掉，解决冲突
			});
		}
		
		span.click(function(){
			show();
			return false;
		});
	
		arrow.find('.combotree-arrow ui-icon ui-icon-triangle-1-s').hover(
			function(){$(this).addClass('combotree-arrow-hover');},
			function(){$(this).removeClass('combotree-arrow-hover');}
		);
		
		return {
			combotree: span,
			content: content
		}
	}
	
	/**
	 * set the value.
	 * node: object, must at lease contains two properties: id and text.
	 */
	function setValue(target, node){
		
		var opts = $.data(target, 'combotree').options;
		var combo = $.data(target, 'combotree').combotree;
		var content = $.data(target, 'combotree').content;
		
		var oldValue = combo.find('input.combotree-value').val();
		
		var root = content.find('>ul');
		var node1 = $('div.tree-node[node-id='+node.id+']', root);
		
		root.__tree('select', node1[0]);
		
		var _id = node.id ;
		var _text = node.text||(node1[0]?node1.text():'') ;
		
		combo.find('input.combotree-value').val(_id);
		combo.find('input.combotree-text').val(_text);
		
		if(_id && _text){
			$(target).empty().append("<option value='' selected></option>").append("<option value='"+_id+"'>"+_text+"</option>") ;
			$(target).val(node.id) ;
		}
			
		
		if (oldValue != node.id){
			opts.onChange.call(target, node.id, oldValue);
		}
	}
	
	function getValue(target){
		var combo = $.data(target, 'combotree').combotree;
		var value = combo.find('input.combotree-value').val();
		var text  = combo.find('input.combotree-text').val();
		return {value:value,text:text} ;
	}
	
	/**
	 * reload the tree panel
	 */
	function reload(target, url){
		var opts = $.data(target, 'combotree').options;
		var content = $.data(target, 'combotree').content;
		if (url){
			opts.url = url;
		}
		content.find('>ul').__tree({url:opts.url}).__tree('reload');
	}
	
	function destroy(target){
		$(target).next(".combotree").remove() ;
	}
	
	$.fn.__combotree = function(options, param){
		if (typeof options == 'string'){
			switch(options){
				case 'setValue':
					return this.each(function(){
						setValue(this, param);
					});
				case 'reload':
					return this.each(function(){
						reload(this, param);
					});
				case 'destroy':
					return this.each(function(){
						destroy(this);
					});
				case 'getValue':
					var target = null ;
					var val = this.each(function(){
						target = this ;
					});
					
					return getValue(target,param)
			}
		}
		
		options = options || {};
		
		return this.each(function(){

			var state = $.data(this, 'combotree');
			
			if (state){
				$.extend(state.options, options);
			} else {
				var r = init(this);
				state = $.data(this, 'combotree', {
					options: $.extend({}, $.fn.__combotree.defaults, {
						width: (parseInt($(this).css('width')) || 'auto'),
						treeWidth: $(this).attr('treeWidth'),
						treeHeight: ($(this).attr('treeHeight') || 200),
						url: $(this).attr('url')
					}, options),
					combotree: r.combotree,
					content: r.content
				});
			}
			
			setSize(this);
		});
	};
	
	$.fn.__combotree.defaults = {
		width:'auto',
		treeWidth:null,
		treeHeight:200,
		url:null,
		onSelect:function(node){},
		onChange:function(newValue,oldValue){}
	};
})(jQuery);

/**
 * tree - jQuery EasyUI
 * 
 * Licensed under the GPL:
 *   http://www.gnu.org/licenses/gpl.txt
 *
 * Copyright 2010 stworthy [ stworthy@gmail.com ] 
 * 
 * Node is a javascript object which contains following properties:
 * 1 id: An identity value bind to the node.
 * 2 text: Text to be showed.
 * 3 attributes: Custom attributes bind to the node.
 * 4 target: Target DOM object.
 */
(function($){
	var clz = {
		hover:'ui-state-hover combotree-hover',//'tree-node-hover',
		selected:'ui-state-active combotree-active',//'tree-node-selected'
		selectedClz:'.combotree-active'
	}
	var nullNodeInit = false ;
	/**
	 * wrap the <ul> tag as a tree and then return it.
	 */
	function wrapTree(target){
		var tree = $(target);
		tree.addClass('tree');
		
		wrapNode(tree, 0);
		
		function wrapNode(ul, depth){
			$('>li', ul).each(function(){
				var node = $('<div class="tree-node"></div>').prependTo($(this));
				var text = $('>span', this).addClass('tree-title').appendTo(node).text();
				$.data(node[0], 'tree-node', {
					text: text
				});
				var subTree = $('>ul', this);
				if (subTree.length){
					$('<span class="tree-folder tree-folder-open"></span>').prependTo(node);
					$('<span class="tree-hit tree-expanded"></span>').prependTo(node);
					wrapNode(subTree, depth+1);
				} else {
					$('<span class="tree-file"></span>').prependTo(node);
					$('<span class="tree-indent"></span>').prependTo(node);
				}
				for(var i=0; i<depth; i++){
					$('<span class="tree-indent"></span>').prependTo(node);
				}
			});
		}
		return tree;
	}
	
	function expandNode(target, node){
		var opts = $.data(target, 'tree').options;
		
		var hit = $('>span.tree-hit', node);
		if (hit.length == 0) return;	// is a leaf node
		
		if (hit.hasClass('tree-collapsed')){
			hit.removeClass('tree-collapsed tree-collapsed-hover').addClass('tree-expanded');
			hit.next().addClass('tree-folder-open');
			var ul = $(node).next();
			if (ul.length){
				if (opts.animate){
					ul.slideDown();
				} else {
					ul.css('display','block');
				}
			} else {
				var id = $.data($(node)[0], 'tree-node').id;
				var subul = $('<ul></ul>').insertAfter(node);
				request(target, subul, {id:id});	// request children nodes data
			}
		}
	}
	
	function collapseNode(target, node){
		var opts = $.data(target, 'tree').options;
		
		var hit = $('>span.tree-hit', node);
		if (hit.length == 0) return;	// is a leaf node
		
		if (hit.hasClass('tree-expanded')){
			hit.removeClass('tree-expanded tree-expanded-hover').addClass('tree-collapsed');
			hit.next().removeClass('tree-folder-open');
			if (opts.animate){
				$(node).next().slideUp();
			} else {
				$(node).next().css('display','none');
			}
		}
	}
	
	function toggleNode(target, node){
		var hit = $('>span.tree-hit', node);
		if (hit.length == 0) return;	// is a leaf node
		
		if (hit.hasClass('tree-expanded')){
			collapseNode(target, node);
		} else {
			expandNode(target, node);
		}
	}
	
	function bindTreeEvents(target){
		var opts = $.data(target, 'tree').options;
		var tree = $.data(target, 'tree').__tree;
		
		$('.tree-node', tree).unbind('.tree').bind('click.tree', function(){
			$(clz.selectedClz, tree).removeClass(clz.selected);
			$(this).addClass(clz.selected);
			
			if (opts.onClick){
				var target = this;	// the target HTML DIV element
				var data = $.data(this, 'tree-node');
				opts.onClick.call(this, {
					id: data.id,
					text: data.text,
					attributes: data.attributes,
					target: target
				});
			}
			
			return false;
		}).bind('mouseenter.tree', function(){
			$(this).addClass(clz.hover);
			return false;
		}).bind('mouseleave.tree', function(){
			$(this).removeClass(clz.hover);
			return false;
		});
		
		$('.tree-hit', tree).unbind('.tree').bind('click.tree', function(){
			var node = $(this).parent();
			toggleNode(target, node);
			return false;
		}).bind('mouseenter.tree', function(){
			if ($(this).hasClass('tree-expanded')){
				$(this).addClass('tree-expanded-hover');
			} else {
				$(this).addClass('tree-collapsed-hover');
			}
		}).bind('mouseleave.tree', function(){
			if ($(this).hasClass('tree-expanded')){
				$(this).removeClass('tree-expanded-hover');
			} else {
				$(this).removeClass('tree-collapsed-hover');
			}
		});
	}
	
	function loadData(ul, data){
		var li = $('<li></li>').appendTo(ul);//空节点
		var node = $('<div class="tree-node"></div>').appendTo(li);
		node.attr('node-id','');
		$.data(node[0], 'tree-node', {
			id: '',
			text: '',
			attributes: {}
		});
		
		function appendNodes(ul, children, depth){
			for(var i=0; i<children.length; i++){
				var li = $('<li></li>').appendTo(ul);
				var item = children[i];
				
				// the node state has only 'open' or 'closed' attribute
				if (item.state != 'open' && item.state != 'closed'){
					item.state = 'open';
				}
				
				var node = $('<div class="tree-node"></div>').appendTo(li);
				node.attr('node-id', item.id);
				
				// store node attributes
				$.data(node[0], 'tree-node', {
					id: item.id,
					text: item.text,
					attributes: item.attributes
				});
				
				$('<span class="tree-title"></span>').html(item.text).appendTo(node);
				if (item.children){
					var subul = $('<ul></ul>').appendTo(li);
					if (item.state == 'open'){
						$('<span class="tree-folder tree-folder-open"></span>').addClass(item.iconCls).prependTo(node);
						$('<span class="tree-hit tree-expanded"></span>').prependTo(node);
					} else {
						$('<span class="tree-folder"></span>').addClass(item.iconCls).prependTo(node);
						$('<span class="tree-hit tree-collapsed"></span>').prependTo(node);
						subul.css('display','none');
					}
					appendNodes(subul, item.children, depth+1);
				} else {
					if (item.state == 'closed'){
						$('<span class="tree-folder"></span>').addClass(item.iconCls).prependTo(node);
						$('<span class="tree-hit tree-collapsed"></span>').prependTo(node);
					} else {
						$('<span class="tree-file"></span>').addClass(item.iconCls).prependTo(node);
						$('<span class="tree-indent"></span>').prependTo(node);
					}
				}
				for(var j=0; j<depth; j++){
					$('<span class="tree-indent"></span>').prependTo(node);
				}
			}
		}

		var depth = $(ul).prev().find('>span.tree-indent,>span.tree-hit').length;
		appendNodes(ul, data, depth);
	}
	
	/**
	 * request remote data and then load nodes in the <ul> tag.
	 */
	function request(target, ul, param){

		var opts = $.data(target, 'tree').options;
		
		var service_param = {};
		
		var folder = $(ul).prev().find('>span.tree-folder');
		folder.addClass('tree-loading');
		
		//为了使用统一的数据服务，通过传递命令字来识别是哪个控件
		
		service_param = $.extend({}, opts.params,opts.params.params);
	
		service_param["childsKey"] = 'children';
    	opts.url = opts.url || "~/dataservice";

    	if (!opts.url) return;
    	
    	$.dataservice(service_param.CommandName,service_param,{
    		success: function(data){
				folder.removeClass('tree-loading');
				loadData(ul, data);
				bindTreeEvents(target);

				//设置默认值
				if( $(opts.target).attr('defaultValue') ){
					$(opts.target).comboTree().setValue({id:$(opts.target).attr('defaultValue')}) ;
				}
				
				if (opts.params&&opts.params.onLoadSuccess){
					opts.params.onLoadSuccess.apply(this, arguments);
				}
			},
			error: function(){
				folder.removeClass('tree-loading');
				if (opts.onLoadError){
					opts.onLoadError.apply(this, arguments);
				}
			}
    	},{url:opts.url}) ;
	}
	
	/**
	 * Get the selected node data which contains following properties: id,text,attributes,target
	 */
	function getSelectedNode(target){
		var node = $(target).find('div'+clz.selectedClz);
		if (node.length){
			return $.extend({}, $.data(node[0], 'tree-node'), {
				target: node[0]
			});
		} else {
			return null;
		}
	}
	
	/**
	 * Append nodes to tree.
	 * The param parameter has two properties:
	 * 1 parent: DOM object, the parent node to append to.
	 * 2 data: array, the nodes data.
	 */
	function appendNodes(target, param){
		var node = $(param.parent);
		var ul = node.next();
		if (ul.length == 0){
			ul = $('<ul></ul>').insertAfter(node);
		}
		
		// ensure the node is a folder node
		if (param.data && param.data.length){
			var nodeIcon = node.find('span.tree-file');
			if (nodeIcon.length){
				nodeIcon.removeClass('tree-file').addClass('tree-folder');
				var hit = $('<span class="tree-hit tree-expanded"></span>').insertBefore(nodeIcon);
				if (hit.prev().length){
					hit.prev().remove();
				}
			}
		}
		
		loadData(ul, param.data);
		bindTreeEvents(target);
	}
	
	/**
	 * Remove node from tree. 
	 * param: DOM object, indicate the node to be removed.
	 */
	function removeNode(target, param){
		var node = $(param);
		var li = node.parent();
		var ul = li.parent();
		li.remove();
		if (ul.find('li').length == 0){
			var node = ul.prev();
			node.find('.tree-folder').removeClass('tree-folder').addClass('tree-file');
			node.find('.tree-hit').remove();
			$('<span class="tree-indent"></span>').prependTo(node);
			if (ul[0] != target){
				ul.remove();
			}
		}
	}
	
	/**
	 * select the specified node.
	 * param: DOM object, indicate the node to be selected.
	 */
	function selectNode(target, param){
		$('div'+clz.selectedClz, target).removeClass(clz.selected);
		$(param).addClass(clz.selected);
	}
	
	
	$.fn.__tree = function(options, param){
		if (typeof options == 'string'){
			switch(options){
				case 'reload':
					return this.each(function(){
						$(this).empty();
						request(this, this);
					});
				case 'getSelected':
					return getSelectedNode(this[0]);
				case 'select':
					return this.each(function(){
						selectNode(this, param);
					});
				case 'collapse':
					return this.each(function(){
						collapseNode(this, $(param));	// param is the node object
					});
				case 'expand':
					return this.each(function(){
						expandNode(this, $(param));		// param is the node object
					});
				case 'append':
					return this.each(function(){
						appendNodes(this, param);
					});
				case 'remove':
					return this.each(function(){
						removeNode(this, param);
					});
			}
		}
		
		
		var options = options || {};
		return this.each(function(){
			var state = $.data(this, 'tree');
			var opts;
			if (state){
				opts = $.extend(state.options, options);
				state.options = opts;
			} else {
				
				opts = $.extend({}, $.fn.__tree.defaults, {
					url:$(this).attr('url'),
					animate:($(this).attr('animate') == 'true')
				}, options);
				$.data(this, 'tree', {
					options: opts,
					tree: wrapTree(this)
				});
				request(this, this);
			}
			
//			if (opts.url){
//				$(this).empty();
//				request(this, this);
//			}
			bindTreeEvents(this);
		});
	};
	
	$.fn.__tree.defaults = {
		url: null,
		animate: false,
		
		onLoadSuccess: function(){},
		onLoadError: function(){},
		onClick: function(node){}	// node: id,text,attributes,target
	};
	
	
	$.comboTreeInit = function(jqueryObj,json4Options){
		jqueryObj.__combotree(json4Options);
	};
	
	$.fn.comboTree = function(json_obj){
		var ocombotreeWidget = new combotreeWidget();
		ocombotreeWidget.init($(this),json_obj);
		return ocombotreeWidget;
	};
	
	combotreeWidget = function(){
		this.$ = null;
		
		this.init = function(jquery_obj,json_obj){
			this.$ = jquery_obj;
			this.options = json_obj ;
			if(json_obj != undefined){
				 this.$.__combotree(json_obj);
			}
			return this.$ ;
		};
		
		this.setValue = function(json_obj){
			this.$.__combotree('setValue',json_obj);
		};
		
		this.getValue = function(){
			return this.$.__combotree('getValue');
		};
		
		this.reload = function(options){
			this.$.__combotree('destroy') ;
			this.options = $.extend(this.options,options) ;
			return this.init(this.$,this.options) ;
		};
	};
			
})(jQuery);